package tr.edu.ege.communicator.util;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Utility class for TCP-IP connection point.
 * 
 * @author Onur ULUSU
 */
public class IPFinder {

	/**
	 * IP string of the loopback address ("127.0.0.1").
	 */
	public static final String LOOPBACK_IP = "127.0.0.1";

	private static final String IP_REGEX = "([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})";

	/**
	 * Finds the network IP address of this local machine.
	 * 
	 * @return IP address that is exit point of this local machine.
	 */
	public static InetAddress findNetworkIP() {
		try {
			// get all network interfaces...
			Enumeration<NetworkInterface> networkInterfaces = NetworkInterface
					.getNetworkInterfaces();

			while (networkInterfaces.hasMoreElements()) {
				// get next interface...
				NetworkInterface netInterface = (NetworkInterface) networkInterfaces
						.nextElement();
				// get all ip addresses...
				Enumeration<InetAddress> ipAddresses = netInterface
						.getInetAddresses();

				return findNetworkEndpoint(ipAddresses);
			}
		} catch (Exception e) {
		}

		return null;
	}

	/**
	 * Finds the network endpoint address in the given ip address list.
	 * 
	 * @param ipAddresses
	 *            enumaration to find proper ip in.
	 * @return found network endpoint address.
	 * @throws UnknownHostException
	 */
	private static InetAddress findNetworkEndpoint(
			Enumeration<InetAddress> ipAddresses) throws UnknownHostException {
		while (ipAddresses.hasMoreElements()) {
			// get next ip address...
			InetAddress ipAddress = (InetAddress) ipAddresses.nextElement();
			// determines if the address is valid...
			if (isValidNetworkAddress(ipAddress)) {
				return ipAddress;
			}
		}

		return InetAddress.getLocalHost();
	}

	/**
	 * Determines the given IP address is the network address of this machine.
	 * In Linux OS {@link InetAddress#getLocalHost()} method may return
	 * "127.0.0.1" loopback address. It is not the network endpoint for the
	 * machine. So this method cannot accept the loopback address as network
	 * endpoint.
	 * 
	 * @param ipAddress
	 *            ip address to check.
	 * @return <code>true</code> if the given address is a valid network
	 *         endpoint.
	 */
	private static boolean isValidNetworkAddress(InetAddress ipAddress) {
		// compile the ip address regex...
		Pattern pattern = Pattern.compile(IP_REGEX);
		// match the given ip address...
		Matcher matcher = pattern.matcher(ipAddress.getHostAddress());
		// return match result && ip != "127.0.0.1"
		return (matcher.matches() && !ipAddress.getHostAddress().equals(
				LOOPBACK_IP));
	}

}
